package com.evil.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteUserDepartmentService;
import com.evil.account.mapper.DepartmentMapper;
import com.evil.account.mapper.UserDepartmentMapper;
import com.evil.account.mapper.UserMapper;
import com.evil.account.pojo.entity.Department;
import com.evil.account.pojo.entity.UserDepartment;
import com.evil.account.service.UserDepartmentService;
import com.evil.account.service.UserEnterpriseService;
import com.evil.common.account.dto.FindByIdAndEIdReqDTO;
import com.evil.common.account.dto.department.DepartmentBaseRespDTO;
import com.evil.common.account.dto.user.FindUserIdsByIdReqDTO;
import com.evil.common.account.dto.user.FindUserIdsByIdsReqDTO;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.account.dto.user.UserEnterpriseDTO;
import com.evil.common.account.dto.user.department.*;
import com.evil.common.account.enums.IsManageEnum;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.core.dto.FindByIdReqDTO;
import com.evil.common.core.dto.FindByIdsReqDTO;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * 用户部门表
 * <p>
 * 严格控制一个用户，一个部门，只有一条数据
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class UserDepartmentServiceImpl extends ServiceImpl<UserDepartmentMapper, UserDepartment> implements UserDepartmentService, RemoteUserDepartmentService {

    private final LoginUtil loginUtil;

    private final UserMapper userMapper;

    private final DepartmentMapper departmentMapper;

    private final UserEnterpriseService userEnterpriseService;

    private final AccountLogServiceImpl logService;

    /**
     * 获取企业用户部门列表
     *
     * @param userEnterpriseDTO userEnterpriseDTO
     * @return UserDepartment 列表
     */
    @Override
    public List<UserDepartment> findByEnterpriseUser(UserEnterpriseDTO userEnterpriseDTO) {
        return this.baseMapper.findByUserId(userEnterpriseDTO.getEnterpriseId(), userEnterpriseDTO.getUserId(), true);
    }

    /**
     * 获取指定部门 用户ids
     *
     * @param findByIdReqDTO findByIdReqDTO
     * @return userIds
     */
    @Override
    public List<Long> findUserIdsByDeptId(FindByIdReqDTO findByIdReqDTO) {
        FindUserIdsByIdReqDTO findUserIdsByIdReqDTO;
        if (findByIdReqDTO instanceof FindUserIdsByIdReqDTO) {
            findUserIdsByIdReqDTO = (FindUserIdsByIdReqDTO) findByIdReqDTO;
        } else {
            findUserIdsByIdReqDTO = BeanUtil.copyProperties(findByIdReqDTO, FindUserIdsByIdReqDTO.class);
        }
        return this.baseMapper.findUserIdsByDeptId(findUserIdsByIdReqDTO);
    }

    /**
     * 获取指定部门 用户基础信息列表
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return userIds
     */
    @Override
    public List<UserBaseRespDTO> findUserBasesByDeptIds(FindByIdsReqDTO findByIdsReqDTO) {
        FindUserIdsByIdsReqDTO findUserIdsByIdsReqDTO;
        if (findByIdsReqDTO instanceof FindUserIdsByIdsReqDTO) {
            findUserIdsByIdsReqDTO = (FindUserIdsByIdsReqDTO) findByIdsReqDTO;
        } else {
            findUserIdsByIdsReqDTO = BeanUtil.copyProperties(findByIdsReqDTO, FindUserIdsByIdsReqDTO.class);
        }
        return this.baseMapper.findUserBasesByDeptIds(findUserIdsByIdsReqDTO);
    }

    /**
     * 获取指定部门 用户ids
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return userIds
     */
    @Override
    public List<Long> findUserIdsByDeptIds(FindByIdsReqDTO findByIdsReqDTO) {
        FindUserIdsByIdsReqDTO findUserIdsByIdsReqDTO;
        if (findByIdsReqDTO instanceof FindUserIdsByIdsReqDTO) {
            findUserIdsByIdsReqDTO = (FindUserIdsByIdsReqDTO) findByIdsReqDTO;
        } else {
            findUserIdsByIdsReqDTO = BeanUtil.copyProperties(findByIdsReqDTO, FindUserIdsByIdsReqDTO.class);
        }
        return this.baseMapper.findUserIdsByDeptIds(findUserIdsByIdsReqDTO);
    }

    /**
     * 获取用户部门列表
     *
     * @param findByIdAndEIdReqDTO findByIdAndEIdReqDTO
     * @return UserDepartment
     */
    @Override
    public List<Long> findUserDepartmentByUserIds(FindByIdAndEIdReqDTO findByIdAndEIdReqDTO) {
        return this.baseMapper.findDeptIdsByUserId(findByIdAndEIdReqDTO.getEnterpriseId(), findByIdAndEIdReqDTO.getId(), findByIdAndEIdReqDTO.getFilterDeleted());
    }

    /**
     * 登录用户部门基础信息
     *
     * @return DepartmentBaseRespDTO 列表
     */
    @Override
    public List<DepartmentBaseRespDTO> loginUserDepartmentBases() {
        return this.userDepartmentBases(loginUtil.getLoginUserEnterprise());
    }

    /**
     * 用户部门基础信息
     *
     * @param userEnterpriseDTO userEnterpriseDTO
     * @return DepartmentBaseRespDTO 列表
     */
    @Override
    public List<DepartmentBaseRespDTO> userDepartmentBases(UserEnterpriseDTO userEnterpriseDTO) {
        return this.baseMapper.findByUserEnterprise(userEnterpriseDTO);
    }

    /**
     * 用户部门基础信息
     *
     * @param userEnterpriseDTO userEnterpriseDTO
     * @return UserDepartmentBaseRespDTO 列表
     */
    @Override
    public List<UserDepartmentBaseRespDTO> findUserDepartmentBaseByUserEnterprise(UserEnterpriseDTO userEnterpriseDTO) {
        return this.baseMapper.findUserDepartmentBaseByUserEnterprise(userEnterpriseDTO);
    }

    /**
     * 配置部门主管（单个用户）
     *
     * @param userDeptManageReqDTO userDeptManageReqDTO
     */
    @Override
    public void userDepartmentManager(UserDeptManageReqDTO userDeptManageReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(userDeptManageReqDTO.getEnterpriseId());
        Long userId = userDeptManageReqDTO.getUserId();
        Long departmentId = userDeptManageReqDTO.getDepartmentId();

        // 检查企业管理员
        userEnterpriseService.checkEnterpriseManager(new UserEnterpriseDTO(enterpriseId, userId));

        // 检查部门
        departmentMapper.findById(userDeptManageReqDTO.getDepartmentId());

        // 获取用户部门
        UserDepartment userDepartment = this.baseMapper.findUserDepartment(enterpriseId, userId, false)
                .orElseGet(() -> this.createUserDepartment(enterpriseId, userId, departmentId, userDeptManageReqDTO.getIsManage()));
        userDepartment.setIsDeleted(SwitchEnum.NO.getId());

        logService.saveAndCheck(this.baseMapper, UserDepartment::getUserDepartmentId, userDepartment);
    }

    /**
     * 部门负责人列表
     *
     * @param departmentManagersReqDTO queryDepartmentManager
     * @return DepartmentManagersRespDTO
     */
    @Override
    public DepartmentManagersRespDTO departmentManagerList(DepartmentManagersReqDTO departmentManagersReqDTO) {
        Department department = departmentMapper.findById(departmentManagersReqDTO.getDepartmentId());

        List<Long> managerIds = this.baseMapper.findUserIdsByDeptId(FindUserIdsByIdReqDTO.filterManager(department.getDepartmentId()));
        List<UserBaseRespDTO> managers = userMapper.findBaseByIds(managerIds, true);

        DepartmentManagersRespDTO departmentManagersRespDTO = new DepartmentManagersRespDTO();
        departmentManagersRespDTO.setDepartmentId(department.getDepartmentId());
        departmentManagersRespDTO.setDepartmentName(department.getDepartmentName());
        departmentManagersRespDTO.setParentDepartmentId(department.getParentDepartmentId());
        departmentManagersRespDTO.setManagers(managers);
        return departmentManagersRespDTO;
    }

    /**
     * 配置部门主管（整个部门）
     *
     * @param departmentManagerSettingReqDTO departmentManagerSettingReqDTO
     */
    @Override
    public void departmentManagerSetting(DepartmentManagerSettingReqDTO departmentManagerSettingReqDTO) {
        Long enterpriseId = departmentManagerSettingReqDTO.getEnterpriseId();
        Long departmentId = departmentManagerSettingReqDTO.getDepartmentId();
        List<Long> managers = CollectionUtil.defaultIfEmpty(departmentManagerSettingReqDTO.getManagers(), new ArrayList<>());

        List<UserDepartment> userDepartments = this.baseMapper.findByDepartmentId(departmentId, false);

        Set<Long> existUserIds = new HashSet<>();
        // 主管+未删除的旧主管
        List<UserDepartment> modifies = new ArrayList<>();
        // 处理已存在
        userDepartments.forEach(ud -> {
            existUserIds.add(ud.getUserId());
            // 主管
            if (managers.contains(ud.getUserId())) {
                ud.setIsManage(IsManageEnum.MANAGE.getId());
                ud.setIsDeleted(SwitchEnum.NO.getId());
                modifies.add(ud);
            }
            // 成员
            else {
                // 未删除
                if (SwitchEnum.isClose(ud.getIsDeleted())) {
                    ud.setIsManage(IsManageEnum.UN_MANAGE.getId());
                    modifies.add(ud);
                }
            }
        });

        // 处理不存在
        modifies.addAll(StreamUtil.transListFT(managers, e -> !existUserIds.contains(e),
                e -> this.createUserDepartment(enterpriseId, e, departmentId, IsManageEnum.MANAGE.getId())));

        logService.saveBatchAndCheck(this.baseMapper, UserDepartment::getUserDepartmentId, modifies);
    }

    /**
     * 修改用户部门（覆盖性）
     *
     * @param enterpriseId enterpriseId
     * @param userId       userId
     * @param departments  departments
     */
    @Override
    public void modify(Long enterpriseId, Long userId, List<UserDepartmentReqDTO> departments) {
        List<UserDepartment> userDepartments = this.baseMapper.findByUserId(enterpriseId, userId, false);

        List<UserDepartment> modifies = new ArrayList<>();

        Set<Long> existDepartmentIds = new HashSet<>();
        Set<Long> departmentIds = new HashSet<>();
        if (CollectionUtil.isNotEmpty(departments)) {
            departmentIds = StreamUtil.transSetT(departments, UserDepartmentReqDTO::getDepartmentId);
            List<Department> departmentList = departmentMapper.findByIds(departmentIds, true);
            if (departmentList.size() != departmentIds.size()) {
                throw new BusinessException(RCodeEnum.DEPARTMENT_NOT_EXIST);
            }
        } else {
            departments = new ArrayList<>();
        }
        for (UserDepartment ud : userDepartments) {
            existDepartmentIds.add(ud.getDepartmentId());
            if (departmentIds.contains(ud.getDepartmentId())) {
                // 已存在的--修改为未删除
                ud.setIsDeleted(SwitchEnum.NO.getId());
                modifies.add(ud);
            } else {
                // 未删除，需要删除
                if (SwitchEnum.isOpen(ud.getIsDeleted())) {
                    ud.setIsDeleted(SwitchEnum.YES.getId());
                    modifies.add(ud);
                }
            }
        }
        // 新增
        modifies.addAll(StreamUtil.transListFT(departments, d -> !existDepartmentIds.contains(d.getDepartmentId()),
                d -> this.createUserDepartment(enterpriseId, userId, d.getDepartmentId(), d.getIsManage())));

        logService.saveBatchAndCheck(this.baseMapper, UserDepartment::getUserDepartmentId, modifies);
    }

    /**
     * 部门批量删除用户
     *
     * @param deptUsersReqDTO deptUsersReqDTO
     */
    @Override
    public void deleteUserDepartmentBatch(DeptUsersReqDTO deptUsersReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(deptUsersReqDTO.getEnterpriseId());
        List<UserDepartment> userDepartments = this.baseMapper.findByDepartmentIdUserIds(enterpriseId,
                deptUsersReqDTO.getId(), deptUsersReqDTO.getUserIds(), true);

        // 删除
        userDepartments.forEach(ud -> ud.setIsDeleted(SwitchEnum.YES.getId()));

        logService.saveBatchAndCheck(this.baseMapper, UserDepartment::getUserDepartmentId, userDepartments);
    }

    /**
     * 部门批量新增用户
     *
     * @param deptUsersReqDTO deptUsersReqDTO
     */
    @Override
    public void addUserDepartmentBatch(DeptUsersReqDTO deptUsersReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(deptUsersReqDTO.getEnterpriseId());
        Set<Long> userIds = new HashSet<>(deptUsersReqDTO.getUserIds());

        List<UserDepartment> userDepartments = this.baseMapper.findByDepartmentIdUserIds(enterpriseId,
                deptUsersReqDTO.getId(), deptUsersReqDTO.getUserIds(), false);
        Map<Long, UserDepartment> userDepartmentMap = StreamUtil.toMapK(userDepartments, UserDepartment::getUserId);

        // 已存在的，初始化
        List<UserDepartment> exists = StreamUtil.transListFT(userIds, userDepartmentMap::containsKey, e -> {
            UserDepartment ud = userDepartmentMap.get(e);
            ud.setIsManage(IsManageEnum.UN_MANAGE.getId());
            ud.setIsDeleted(SwitchEnum.NO.getId());
            return ud;
        });

        // 不存在的，新构建
        exists.addAll(StreamUtil.transListFT(userIds, e -> !userDepartmentMap.containsKey(e),
                e -> this.createUserDepartment(enterpriseId, e, deptUsersReqDTO.getId(), IsManageEnum.UN_MANAGE.getId())));

        logService.saveBatchAndCheck(this.baseMapper, UserDepartment::getUserDepartmentId, userDepartments);
    }

    /**
     * 创建 UserDepartment
     *
     * @param enterpriseId enterpriseId
     * @param userId       userId
     * @param departmentId departmentId
     * @param isManage     isManage
     * @return UserDepartment
     */
    private UserDepartment createUserDepartment(Long enterpriseId, Long userId, Long departmentId, Integer isManage) {
        UserDepartment newEntity = new UserDepartment();
        newEntity.setEnterpriseId(enterpriseId);
        newEntity.setUserId(userId);
        newEntity.setDepartmentId(departmentId);
        newEntity.setIsManage(isManage);
        newEntity.setIsDeleted(SwitchEnum.NO.getId());
        return newEntity;
    }
}
